package Team.Yaohuo.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.Charsets;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;


@Slf4j
public class APIUtils {
    public static final String WEBSITE = "https://www.jiandaoyun.com";
    private static boolean retryIfRateLimited = true;
    private String urlGetWidgets;
    private String urlGetFormData1;
    private String urlGetFormData;
    private String urlRetrieveData;
    private String urlUpdateData;
    private String urlCreateData;
    private String urlDeleteData;
    private String urlCreateUSer;
    private String urlCreatePerson;
    private String urlCreatePersonAll;
    private String urlCreateDep;
    private String urlCreateDepAll;
    private String urlGetDepartment;
    private String urlGetPeople;
    private String urlDeletePeople;
    private String urlImportPeople;
    private String deleteAllData;
    private String urlDataBatchCreate;
    private String urlUploadFile;
    private static String apiKey;
    private void initUrl(String appId, String entryId) {
        urlGetWidgets = WEBSITE + "/api/v1/app/" + appId + "/entry/" + entryId + "/widgets";
        urlGetFormData1 = WEBSITE + "/api/v1/app/" + appId + "/entry/" + entryId + "/data_retrieve";
        urlGetFormData = WEBSITE + "/api/v1/app/" + appId + "/entry/" + entryId + "/data";
        urlRetrieveData = WEBSITE + "/api/v1/app/" + appId + "/entry/" + entryId + "/data_retrieve";
        urlUpdateData = WEBSITE + "/api/v3/app/" + appId + "/entry/" + entryId + "/data_update";
        urlCreateData = WEBSITE + "/api/v2/app/" + appId + "/entry/" + entryId + "/data_create";
        urlDeleteData = WEBSITE + "/api/v1/app/" + appId + "/entry/" + entryId + "/data_delete";
        urlCreatePerson = WEBSITE + "/api/v2/user/create";
        urlCreateUSer = WEBSITE + "/api/v2/user/create";
        urlCreateDep = WEBSITE + "/api/v2/department/create";
        urlCreateDepAll = WEBSITE + "/api/v2/department/import";
        urlCreatePersonAll = WEBSITE + "/api/v2/user/import";
        urlGetDepartment = WEBSITE + "/api/v2/department/1/department_list";
        urlGetPeople = WEBSITE + "/api/v2/department/1/member_list";
        urlDeletePeople = WEBSITE + "/api/v2/user/batch_delete";
        urlImportPeople = WEBSITE + "/api/v2/user/import";
        deleteAllData = WEBSITE + "/api/v5/app/entry/data/batch_delete";
        urlDataBatchCreate = WEBSITE + "/api/v1/app/" + appId + "/entry/" + entryId + "/data_batch_create";
        urlUploadFile = WEBSITE + "/api/v1/app/" + appId + "/entry/" + entryId + "/file/get_upload_token";
    }

    /**
     * @param appId   - 应用id
     * @param entryId - 表单id
     * @param apiKey  - apiKey
     */
    public APIUtils(String appId, String entryId, String apiKey) {
        this.apiKey = apiKey;
        this.initUrl(appId, entryId);
    }

    public Map<String, Object> createPerson(Map<String, Object> person) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreatePerson, person);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 获取文件上传的token
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public List<Map<String, Object>> get_upload_token(String transaction_id) {
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("transaction_id", transaction_id);
        List<Map<String, Object>> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlUploadFile, requestData);
            data = (List<Map<String, Object>>) result.get("token_and_url_list");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    public Map<String, Object> createDep(Map<String, Object> person) {
        Map<String, Object> data = null;

        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreatePerson, person);
            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


    public static HttpClient getSSLHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            //信任所有
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        }).build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }

    /**
     * 获取部门成员信息
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> deletePeopleBatch(Map<String, Object> map) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlDeletePeople, map);
            return result;
//            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 获取请求头信息
     *
     * @return
     */
    public static Header[] getHttpHeaders() {
        List<Header> headerList = new ArrayList<Header>();
        headerList.add(new BasicHeader("Authorization", "Bearer " + apiKey));
        headerList.add(new BasicHeader("Content-Type", "application/json;charset=utf-8"));
        return headerList.toArray(new Header[headerList.size()]);
    }

    /**
     * 查询人员信息
     *
     * @param username - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> findPerson(String username) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", WEBSITE + "/api/v2/user/" + username + "/user_retrieve", new HashMap<>());
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 发送HTTP请求
     *
     * @param method - HTTP动词 { GET|POST }
     * @param url    - 请求路径
     * @param data   - 请求的数据
     * @throws Exception
     */
    public static Object sendRequest(String method, String url, Map<String, Object> data) throws Exception {
        HttpClient client = getSSLHttpClient();
        Header[] headers = getHttpHeaders();
        HttpRequestBase request;
        method = method.toUpperCase();
        if ("POST".equals(method)) {
            // POST请求
            request = new HttpPost(url);
            ObjectMapper mapper = new ObjectMapper();
            HttpEntity entity = new StringEntity(mapper.writeValueAsString(data), Charsets.UTF_8);
            String entityContent = EntityUtils.toString(entity, Charset.forName(HTTP.UTF_8));

            log.info("HttpEntity的内容:{}", entityContent);

            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(data);

            ((HttpPost) request).setEntity(entity);
        } else {
            throw new RuntimeException("不支持的HTTP动词");
        }
        // 设置请求头
        request.setHeaders(headers);
        // 发送请求并获取返回结果
        HttpResponse response = client.execute(request);
        int statusCode = response.getStatusLine().getStatusCode();
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> result = (Map<String, Object>) mapper.readValue(response.getEntity().getContent(), Object.class);
        Thread.sleep(100);
        if (statusCode >= 400) {
            // 请求错误
            if ((Integer) result.get("code") == 8303 && retryIfRateLimited) {
                // 频率超限，1s后重试
                Thread.sleep(1000);
                System.out.println("频率超限，1s后重试");
                return sendRequest(method, url, data);
            } else {
                return result;
            }
        } else {
            // 处理返回结果
            return result;
        }

    }


    /**
     * 获取表单字段
     *
     * @return 表单字段
     */
    public List<Map<String, Object>> getFormWidgets() {
        List<Map<String, Object>> widgets = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlGetWidgets, new HashMap<String, Object>());
            widgets = (List<Map<String, Object>>) result.get("widgets");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return widgets;
    }


    public List<Map<String, Object>> createUser(String username, String name, Integer[] departments) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("username", username);
            requestData.put("name", name);
            requestData.put("departments", departments);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreateUSer, requestData);
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (List<Map<String, Object>>) data;
    }


    public String importUser(JSONArray user_j) {
        String data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            List<Map<String, Object>> users = new LinkedList<>();
            Map<String, Object> user = new HashMap<>();
            for (Object o : user_j) {
                HashMap<String, Object> jsonObject = (HashMap<String, Object>) o;
                user.put("username", jsonObject.get("username"));
                user.put("name", jsonObject.get("name"));
                user.put("departments", jsonObject.get("departments"));
                users.add(user);
            }
            requestData.put("users", users);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlImportPeople, requestData);
            data = (String) result.get("status");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 查询单条
     */
    public List<Map<String, Object>> getFormData1(String dataId) {
        List<Map<String, Object>> data = null;
        try {
            // 构造请求数据
            Map<String, Object> requestData = new HashMap<String, Object>() {
                {
                }
            };
            if (dataId != null) {
                requestData.put("data_id", dataId);
            }
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlGetFormData1, requestData);
            data = (List<Map<String, Object>>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


    /**
     * 按条件获取表单数据
     *
     * @param limit  - 数据条数
     * @param fields - 显示的字段
     * @param filter - 过滤条件
     * @param dataId - 上次取数的最后一个数据id
     * @return - 返回的数据
     */
    public List<Map<String, Object>> getFormData(final int limit, final String[] fields, final Map<String, Object> filter, String dataId) {
        List<Map<String, Object>> data = null;
        try {
            // 构造请求数据
            Map<String, Object> requestData = new HashMap<String, Object>() {
                {
                    put("limit", limit);
                    put("fields", fields);
                    put("filter", filter);
                }
            };
            if (dataId != null) {
                requestData.put("data_id", dataId);
            }
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlGetFormData, requestData);
            data = (List<Map<String, Object>>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 按条件获取全部表单数据
     * @param fields 字段
     * @param filter 过滤条件
     * @return  表单数据
     */
    public List<Map<String, Object>> getAllFormData(String[] fields, Map<String, Object> filter) {
        List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>();
        String offset = null;
        do {
            List<Map<String, Object>> data = this.getFormData(100, fields, filter, offset);
            // 获取返回的数据
            if (data == null || data.isEmpty()) {
                // 已经获取全部的数据
                offset = null;
            } else {
                // 获取最后一条数据的id
                offset = (String) data.get(data.size() - 1).get("_id");
                dataList.addAll(data);
            }
        } while (offset != null);
        return dataList;
    }


    /**
     * 搜索单条数据
     *
     * @param dataId - 要查询的数据id
     * @return 表单数据
     */
    public Map<String, Object> retrieveData(String dataId) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("data_id", dataId);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlRetrieveData, requestData);
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 新增部门
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> createDataDep(Map<String, Object> requestData) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreateDep, requestData);
//            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


    /**
     * 批量创建部门
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> createDataDepAll(Map<String, Object> requestData) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreateDepAll, requestData);
//            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


    /**
     * 批量删除数据
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> deleteAllData(Map<String, Object> ids) {
        Map<String, Object> data = null;
        try {
            Object result = this.sendRequest("POST", deleteAllData, ids);
//            data = (Map<String, Object>) result.get("department");
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 批量新增数据
     *
     * @return 新增结果
     */
    public Map<String, String> dataBatchCreate(JSONArray data_list, Boolean is_start_workflow, Boolean is_start_trigger) {
        Map<String, String> result = null;
        try {
            UUID uuid = UUID.randomUUID();
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("transaction_id", uuid.toString());
            requestData.put("data_list", data_list);
            if (is_start_workflow != null) {
                requestData.put("is_start_workflow", is_start_workflow);
            }
            if (is_start_trigger != null) {
                requestData.put("is_start_trigger", is_start_trigger);
            }

            result = (Map<String, String>) this.sendRequest("POST", urlDataBatchCreate, requestData);
            result.put("transaction_id", uuid.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 批量创建人员
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> createDataPersonAll(Map<String, Object> requestData) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreatePersonAll, requestData);
            System.out.println(result);
            return result;
//            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取部门信息
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> getDepartment() {
        Map<String, Object> map = new HashMap<>();
        map.put("dept_no",1);
        map.put("has_child", true);
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlGetDepartment, map);
            System.out.println(result);
            return result;
//            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


    /**
     * 获取部门成员信息
     *
     * @param - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> getDepartmentPerson(String dno) {
        Map<String, Object> map = new HashMap<>();
//        map.put("has_child",1);
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", WEBSITE + "/api/v2/department/" + dno + "/member_list", map);
            return result;
//            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    public Map<String, Object> deleteDepartment(Integer no) {
        Map<String, Object> map = new HashMap<>();
        map.put("has_child", 1);
        Map<String, Object> data = null;
        try {
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", WEBSITE + "/api/v2/department/" + no + "/delete", new HashMap<>());
            System.out.println(result);
            return result;
//            data = (Map<String, Object>) result.get("department");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


//    /**
//     * 新增部门
//     * @param - 创建数据内容
//     * @return 更新后的数据
//     */
//    public Map<String, Object> createDataDep (Map<String, Object> requestData) {
//        Map<String, Object> data = null;
//        try {
//            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST",urlCreateDep, requestData);
//            data = (Map<String, Object>) result.get("data");
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return  data;
//    }


    /**
     * 创建单条数据
     *
     * @param rawData - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> createData(JSONObject rawData) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("data", rawData);
            requestData.put("is_start_trigger", true);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreateData, requestData);
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 创建单条数据
     * @param rawData - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> createData (Map<String, Object> rawData) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("data", rawData);
            requestData.put("is_start_workflow",true);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST",urlCreateData, requestData);
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  data;
    }

    /**
     * 创建单条触发数据
     *
     * @param rawData - 创建数据内容
     * @return 更新后的数据
     */
    public Map<String, Object> createData1(Map<String, Object> rawData) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("data", rawData);
            requestData.put("is_start_workflow", true);
            requestData.put("is_start_trigger", true);

            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlCreateData, requestData);
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }


    /**
     * 获取所有的人在简道云
     *
     * @return 更新后的数据
     */
    public List<Map<String, Object>> getAllPeople() {
        List<Map<String, Object>> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("has_child", true);
//            System.out.println("准备发起HTTP请求！"+urlGetPeople);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlGetPeople, requestData);
            data = (List<Map<String, Object>>) result.get("users");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 更新单条数据
     *
     * @return 更新结果
     */
    public Map<String, Object> updateData(String dataId, Map<String, Object> update) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("data_id", dataId);
            requestData.put("data", update);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlUpdateData, requestData);
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }
    /**
     * 更新单条数据
     * @return 更新结果
     */
    public Map<String, Object> updateData (String dataId, Map<String, Object> update,String transaction_id) {
        Map<String, Object> data = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("data_id", dataId);
            requestData.put("data", update);
            requestData.put("is_start_trigger",true);
            requestData.put("transaction_id",transaction_id);
            Map<String, Object> result = (Map<String, Object>) this.sendRequest("POST", urlUpdateData, requestData);
            data = (Map<String, Object>) result.get("data");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 删除单条数据
     *
     * @return 删除结果
     */
    public Map<String, String> deleteData(String dataId) {
        Map<String, String> result = null;
        try {
            Map<String, Object> requestData = new HashMap<String, Object>();
            requestData.put("data_id", dataId);
            result = (Map<String, String>) this.sendRequest("POST", urlDeleteData, requestData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


}